import 'package:flutter/services.dart';

final hyoukaAssistant = HyoukaAssistant._();

class HyoukaAssistant {
  static final _instance = HyoukaAssistant._interval();

  late final MethodChannel _methodChannel;

  factory HyoukaAssistant._() => _instance;

  HyoukaAssistant._interval() {
    final channelName = "cn.cjlmonster.hyouka/assistant";
    _methodChannel = MethodChannel(channelName);
    _methodChannel.setMethodCallHandler((call) async {
      final params = ChannelParams(call.arguments);
      final result = await _onMethodReceivedListener?.onMethodReceived(params);
      _methodChannel.invokeMethod("flutterCallback", params.toDataMap(result));
    });
  }

  OnMethodReceivedListener? _onMethodReceivedListener;

  void setOnMethodReceivedListener(OnMethodReceivedListener? listener) {
    _onMethodReceivedListener = listener;
  }

  Future<bool> openAssistantSheet(String url, [int marginTop = 57]) async {
    return await _methodChannel.invokeMethod("openAssistantSheet", {
      "url": url,
      "marginTop": marginTop,
    });
  }

  Future<bool> openUrl(String url, [Map? query]) async {
    return await _methodChannel.invokeMethod("openUrl", {"url": url, "query": query});
  }

  Future<void> removeAllActivity() async {
    return await _methodChannel.invokeMethod("removeAllActivity");
  }

  void recognizeReceived(int key, Map data) {
    _methodChannel.invokeMethod("recognizeReceived", {'key': key, 'data': data});
  }
}

abstract mixin class OnMethodReceivedListener {
  Future<dynamic> onMethodReceived(ChannelParams params);
}

class ChannelParams {
  late final int key;
  late final int id;
  late final String method;
  late final String callback;
  late final Map extras;

  ChannelParams(args) {
    key = args['key'] as int;
    id = args['id'] as int;
    method = args['method'] as String;
    callback = args['callback'] as String;
    extras = args['extras'] as Map? ?? {};
  }

  Map toDataMap(result) {
    return {
      'key': key,
      'id': id,
      'method': method,
      'callback': callback,
      'data': {...extras, ...(result ?? {})}
    };
  }
}
